<template>
  <div style="width: 100%">
    <!-- 输入区域 -->
    <el-input
      v-model="selectedAddress"
      type="textarea"
      :rows="3"
      placeholder="已选位置"
      readonly
      style="width: 100%"
    />
    <el-button @click="openMapDialog" class="mt-2">选择位置</el-button>

    <!-- 地图弹窗 -->
    <el-dialog
      v-model="dialogVisible"
      title="位置选择"
      width="60%"
      height="80%"
      @closed="destroyMap"
    >
      <div class="map-container">
        <!-- 搜索栏 -->
        <el-autocomplete
          v-model="searchText"
          placeholder="输入地址搜索"
          :fetch-suggestions="querySearch"
          @select="handleSelect"
          clearable
          class="mb-1"
        />
        <!-- 提示信息 -->
        <div class="map-wrapper" v-if="loading">地图正在初始化中......</div>

        <!-- 地图容器 -->
        <div ref="mapContainer" class="map-wrapper"></div>

        <!-- 位置信息 -->
        <div class="position-info mt-4">
          <el-descriptions :column="1" border>
            <el-descriptions-item label="地址" label-width="120px">
              {{ currentPosition.address }}
            </el-descriptions-item>
            <el-descriptions-item label="经度">
              {{ currentPosition.lng }}
            </el-descriptions-item>
            <el-descriptions-item label="纬度">
              {{ currentPosition.lat }}
            </el-descriptions-item>
          </el-descriptions>
        </div>

        <!-- 操作按钮 -->
        <div class="dialog-footer mt-4">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="confirmSelection">确定</el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
/**
 * 百度位置选择器
 * 坐标格式：BD09
 * 配置选项：ak
 * 展示组件：ra-view-bmap
 * 坐标转换：推荐 gcoord (系统已经集成)
 */
import gcoord from 'gcoord';
import { ElMessageBox } from 'element-plus';
import { ref, reactive, watch, nextTick, onMounted } from 'vue'; // 确保所有 Vue API 都已导入

const ak = import.meta.env.VITE_APP_MAP_BMAP_AK; // 百度地图密钥
const zoom = 16;
const loading = ref(false);
const mapInstance = ref(null);
const geocoder = ref(null);
const marker = ref(null);
const mapContainer = ref(null);

// 响应式数据
const dialogVisible = ref(false);
const searchText = ref('');
const selectedAddress = ref(''); // 用于显示在输入框中的地址文本
const currentPosition = reactive({
  address: '',
  lng: null,
  lat: null,
});

const props = defineProps({
  modelValue: {
    type: [Object, String], // 允许 modelValue 是对象或字符串
    default: null,
  },
});

const emit = defineEmits(['update:modelValue']);

watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal) {
      try {
        // modelValue 可能是一个 JSON 字符串或一个对象
        const parsedValue =
          typeof newVal === 'string' ? JSON.parse(newVal) : newVal;
        if (parsedValue && parsedValue.address) {
          selectedAddress.value = parsedValue.address; // 只显示地址
          // 同步内部状态，以便地图打开时使用
          currentPosition.address = parsedValue.address;
          currentPosition.lng = parsedValue.lng;
          currentPosition.lat = parsedValue.lat;
        } else {
          selectedAddress.value = '';
        }
      } catch (e) {
        console.error('解析 modelValue 失败:', e);
        selectedAddress.value = '';
      }
    } else {
      selectedAddress.value = '';
    }
  },
  { immediate: true, deep: true },
);

// 动态加载百度地图API
const loadBMap = () => {
  return new Promise((resolve) => {
    if (!ak) {
      ElMessageBox.alert('请先配置百度地图ak', '提示');
      return;
    }
    if (window.BMapGL) return resolve();

    window.BMapGL_loadScriptTime = Date.now();
    window.BMapGL = {};
    window.BMapGL.callback = () => resolve();

    const script = document.createElement('script');
    script.src = `https://api.map.baidu.com/api?type=webgl&v=1.0&ak=${ak}&callback=BMapGL.callback`;
    document.head.appendChild(script);
  });
};

const initMap = async () => {
  loading.value = true;
  await loadBMap();

  mapInstance.value = new BMapGL.Map(mapContainer.value, {
    enableMapClick: false,
  });

  let initialPoint;

  // 如果 props.modelValue 中有有效坐标，则使用它作为初始点
  if (currentPosition.lng && currentPosition.lat) {
    initialPoint = new BMapGL.Point(currentPosition.lng, currentPosition.lat);
  } else {
    // 否则，获取当前GPS位置
    const gpsPosition = await getGPSLocation();
    const position = convertLocation(gpsPosition);
    initialPoint = new BMapGL.Point(position.lng, position.lat);
  }

  mapInstance.value.centerAndZoom(initialPoint, zoom);
  mapInstance.value.enableScrollWheelZoom(true);
  updateMarker(initialPoint);

  // 如果 currentPosition 中还没有地址信息，则进行逆地址解析
  if (!currentPosition.address) {
    updatePositionInfo(initialPoint);
  }

  geocoder.value = new BMapGL.Geocoder();
  mapInstance.value.addEventListener('click', handleMapClick);
  loading.value = false;
};

// 地址搜索
const querySearch = async (queryString, cb) => {
  if (!queryString) return cb([]);

  const local = new BMapGL.LocalSearch(mapInstance.value, {
    onSearchComplete: (result) => {
      if (result && result._pois) {
        const suggestions = result._pois.map((item) => ({
          value: item.title + ' (' + item.address + ')',
          ...item.point,
        }));
        cb(suggestions);
      } else {
        cb([]);
      }
    },
  });
  local.search(queryString);
};

// 处理地图点击
const handleMapClick = (e) => {
  const point = new BMapGL.Point(e.latlng.lng, e.latlng.lat);
  currentPosition.lng = point.lng;
  currentPosition.lat = point.lat;
  updatePositionInfo(point);
};

// 更新位置信息
const updatePositionInfo = (point) => {
  if (!geocoder.value) {
    geocoder.value = new BMapGL.Geocoder();
  }
  geocoder.value.getLocation(point, (result) => {
    if (result) {
      currentPosition.address = result.address;
      if (result.content && result.content.poi_desc) {
        currentPosition.address += ' (' + result.content.poi_desc + ')';
      }
      updateMarker(point);
    }
  });
};

// 选择搜索结果
const handleSelect = (item) => {
  let bdPoint = new BMapGL.Point(item.lng, item.lat);
  mapInstance.value.centerAndZoom(bdPoint, zoom);
  currentPosition.lng = bdPoint.lng;
  currentPosition.lat = bdPoint.lat;
  updatePositionInfo(bdPoint);
};

// 更新标记
const updateMarker = (point) => {
  if (marker.value) {
    mapInstance.value.removeOverlay(marker.value);
  }
  marker.value = new BMapGL.Marker(point);
  mapInstance.value.addOverlay(marker.value);
};

// 打开弹窗
const openMapDialog = () => {
  dialogVisible.value = true;
  nextTick(() => {
    // 每次打开都重新初始化地图，确保状态正确
    if (mapInstance.value) {
      destroyMap();
    }
    initMap();
  });
};

// *** 修正 #3: 确认选择时的数据处理 ***
const confirmSelection = () => {
  const addressData = {
    address: currentPosition.address,
    lat: currentPosition.lat,
    lng: currentPosition.lng,
  };
  // 更新输入框的显示值
  selectedAddress.value = addressData.address;
  // 向上层组件发出一个 JSON 字符串
  emit('update:modelValue', JSON.stringify(addressData));
  dialogVisible.value = false;
};

// 销毁地图
const destroyMap = () => {
  if (mapInstance.value) {
    mapInstance.value.destroy();
    mapInstance.value = null;
    geocoder.value = null;
    marker.value = null;
  }
  // 保留 currentPosition 的值，以便下次打开时能恢复
};

// 根据浏览器获得GPS坐标
const getGPSLocation = () => {
  return new Promise((resolve) => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          const currtentLocation = {
            lat: position.coords.latitude,
            lng: position.coords.longitude,
          };
          resolve(currtentLocation);
        },
        () => {
          // 定位失败则默认北京
          resolve({ lat: 39.916527, lng: 116.397128 });
        },
      );
    } else {
      // 不支持地理定位则默认北京
      resolve({ lat: 39.916527, lng: 116.397128 });
    }
  });
};

// 坐标转换
const convertLocation = (point) => {
  const result = gcoord.transform(
    [point.lng, point.lat],
    gcoord.WGS84,
    gcoord.BD09,
  );
  return {
    lng: result[0],
    lat: result[1],
  };
};
</script>

<style scoped>
.map-wrapper {
  height: 500px;
  width: 100%;
  margin: 16px 0;
}

.position-info {
  padding: 12px;
  background: #f5f7fa;
  border-radius: 4px;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}
</style>
